package com.example.voluntary.service.impl;

import com.alibaba.fastjson.JSON;
import com.example.common.constant.MessageConstant;
import com.example.common.context.BaseContext;
import com.example.common.domain.PageResult;
import com.example.common.domain.Result;
import com.example.common.exception.CustomException;
import com.example.user.api.client.AddressCLient;
import com.example.user.domain.vo.UserInfoVO;
import com.example.voluntary.constants.MQConstants;
import com.example.voluntary.domain.dto.ActivityAuditDTO;
import com.example.voluntary.domain.dto.ActivityQueryDTO;
import com.example.voluntary.domain.dto.VoluntarySearchDTO;
import com.example.voluntary.domain.dto.VolunteerActivitiesDTO;
import com.example.voluntary.domain.po.ActivityDoc;
import com.example.voluntary.domain.po.VolunteerActivities;
import com.example.voluntary.domain.po.VolunteerParticipation;
import com.example.voluntary.domain.vo.*;
import com.example.voluntary.mapper.VolunteerActivitiesMapper;
import com.example.voluntary.mapper.VolunteerParticipationMapper;
import com.example.voluntary.service.VolunteerActivitiesService;
import com.example.voluntary.utils.GenerateQrCodeUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.zxing.WriterException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class VolunteerActivitiesServiceImpl implements VolunteerActivitiesService {
    private final VolunteerActivitiesMapper volunteerActivitiesMapper;
    private final VolunteerParticipationMapper volunteerParticipationMapper;
    private final AddressCLient addressCLient;
    private final RestHighLevelClient client;
    private final RabbitTemplate rabbitTemplate;

    /**
     * 创建志愿活动
     *
     * @param volunteerActivitiesDTO
     */
    @Override
    public void createVoluntary(VolunteerActivitiesDTO volunteerActivitiesDTO) {
        VolunteerActivities volunteerActivities = new VolunteerActivities();
        BeanUtils.copyProperties(volunteerActivitiesDTO, volunteerActivities);
        if (volunteerActivities.getActivityImage().isEmpty()) {
            volunteerActivities.setActivityImage("https://example.com/default-image.jpg");
        }
        volunteerActivities.setUserId(BaseContext.getCurrentId());
        volunteerActivities.setCreatedAt(LocalDateTime.now());
        volunteerActivities.setStatus(0);
        volunteerActivities.setCurrentParticipants(0);
        volunteerActivitiesMapper.insert(volunteerActivities);
    }

    /**
     * 查询志愿活动列表
     *
     * @param pageNum
     * @param size
     * @return
     */
    @Override
    public PageResult<VoluntaryVO> getVoluntaryList(Integer pageNum, Integer size) {
        PageHelper.startPage(pageNum, size);
        Page<VoluntaryVO> list = volunteerActivitiesMapper.selectVoluntaryList(pageNum, size);
        PageResult<VoluntaryVO> pageResult = new PageResult<>(list.getTotal(), list.getResult());
        return pageResult;
    }


    /**
     * 添加参加记录
     *
     * @param activityId 活动id
     */
    @Override
    @Transactional
    public void addParticipation(Integer activityId) {
        // 1. 获取当前用户id
        Long currentId = BaseContext.getCurrentId();
        // 2. 查询是否已经参加了该活动
        Integer count = volunteerParticipationMapper.selectParticipation(activityId, currentId);
        if (count > 0) {
            throw new CustomException(MessageConstant.ALREADY_PARTICIPATED); // 使用常量
        }
        // 3. 判断是否可以报名
        VolunteerActivities volunteerActivities = volunteerActivitiesMapper.selectById(activityId);
        // 3.1 判断是否开始报名
        if (volunteerActivities.getRegistrationStartTime().isAfter(LocalDateTime.now())) {
            throw new CustomException(MessageConstant.REGISTRATION_NOT_STARTED); // 使用常量
        }
        // 3.2 判断是否结束报名
        if (volunteerActivities.getRegistrationEndTime().isBefore(LocalDateTime.now())) {
            throw new CustomException(MessageConstant.REGISTRATION_ENDED); // 使用常量
        }
        // 3.3 判断活动人数是否已满
        if (volunteerActivities.getCurrentParticipants() >= volunteerActivities.getMaxParticipants()) {
            throw new CustomException(MessageConstant.PARTICIPANTS_FULL); // 使用常量
        }
        // 4. 创建参加记录
        VolunteerParticipation volunteerParticipation = VolunteerParticipation.builder()
                .activityId(activityId)
                .userId(currentId)
                .duration(0)
                .participationStatus(0)
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();
        volunteerParticipationMapper.insert(volunteerParticipation);

        // 5. 参加活动人数加1
        int updated = volunteerActivitiesMapper.updateActivityCurrentParticipants(volunteerActivities.getActivityId());
        if (updated == 0) {
            // 说明更新失败，可能是人数已满
            throw new CustomException(MessageConstant.PARTICIPANTS_FULL);
        }

    }

    @Override
    public ActivityDetailVO getActivityDetail(Integer activityId) {
        ActivityDetailVO activityDetailVO = new ActivityDetailVO();
        VolunteerActivities volunteerActivities = volunteerActivitiesMapper.selectById(activityId);
        BeanUtils.copyProperties(volunteerActivities, activityDetailVO);
        // 查询参加活动的用户id
        List<Long> userIds = volunteerParticipationMapper.selectUserIdByActivityId(activityId);

        List<VolunteerVO> volunteerVOList = new ArrayList<>();
        userIds.forEach(userId -> {
            VolunteerVO volunteerVO = new VolunteerVO();
            Result<UserInfoVO> result = addressCLient.getVolunteer(userId);
            volunteerVO.setNickname(result.getData().getNickname());
            volunteerVO.setAvatar(result.getData().getAvatar());
            volunteerVOList.add(volunteerVO);
        });
        activityDetailVO.setVolunteers(volunteerVOList);
        return activityDetailVO;
    }


    @Override
    public PageResult<VoluntaryVO> searchVolunteerActivity(VoluntarySearchDTO searchDTO) {
        // 构建Elasticsearch查询
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 构建组合查询条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 多字段搜索示例
        if (StringUtils.hasText(searchDTO.getKeyword())) {
            MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(
                    searchDTO.getKeyword(),
                    "title",
                    "description"
            ).type(MultiMatchQueryBuilder.Type.BEST_FIELDS);
            boolQuery.must(multiMatchQuery);
        }

        // 活动类型精确匹配
        if (searchDTO.getActivityType() != null) {
            boolQuery.must(QueryBuilders.termQuery("activityType", searchDTO.getActivityType()));
        }

        // 活动状态精确匹配
        if (searchDTO.getStatus() != null) {
            boolQuery.must(QueryBuilders.termQuery("status", searchDTO.getStatus()));
        }

        // 设置查询条件
        searchSourceBuilder.query(boolQuery);

        // 设置分页
        int from = (searchDTO.getPage() - 1) * searchDTO.getPageSize();
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(searchDTO.getPageSize());

        // 设置排序规则（可选）
        searchSourceBuilder.sort(new FieldSortBuilder("startTime").order(SortOrder.ASC));

        //  实际的Elasticsearch客户端调用代码
        try {
            // 构建搜索请求
            SearchRequest searchRequest = new SearchRequest("voluntary_activities");
            searchRequest.source(searchSourceBuilder);

            // 执行搜索
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

            // 处理搜索结果
            List<VoluntaryVO> resultList = new ArrayList<>();
            SearchHits hits = searchResponse.getHits();

            for (SearchHit hit : hits) {
                // 获取_source数据
                String sourceAsString = hit.getSourceAsString();
                // 将JSON转换为ActivityDoc对象
                ActivityDoc activityDoc = JSON.parseObject(sourceAsString, ActivityDoc.class);

                VoluntaryVO voluntaryVO = new VoluntaryVO();

                // 复制相同属性的值
                BeanUtils.copyProperties(activityDoc, voluntaryVO);

                // 注意：如果ActivityDoc中已经正确处理了时间字段，则不需要额外处理
                // 只有在ActivityDoc中的时间字段是String类型时才需要以下转换
            /*
            if (activityDoc.getStartTime() instanceof String) {
                String startTimeStr = (String) activityDoc.getStartTime();
                if (StringUtils.hasText(startTimeStr)) {
                    voluntaryVO.setStartTime(LocalDateTime.parse(startTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            }

            if (activityDoc.getEndTime() instanceof String) {
                String endTimeStr = (String) activityDoc.getEndTime();
                if (StringUtils.hasText(endTimeStr)) {
                    voluntaryVO.setEndTime(LocalDateTime.parse(endTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            }
            */

                resultList.add(voluntaryVO);
            }

            // 获取总记录数
            long totalHits = hits.getTotalHits().value;

            // 返回分页结果
            return new PageResult<>(totalHits, resultList);

        } catch (IOException e) {
            log.error("Elasticsearch查询失败", e);
            throw new CustomException("搜索志愿活动失败");
        } catch (Exception e) {
            log.error("处理搜索结果时发生错误", e);
            throw new CustomException("处理搜索结果时发生错误");
        }

    }

    @Override
    public void syncVolunteerActivitiesToElasticsearch() {
        List<ActivityDoc> activities = volunteerActivitiesMapper.selectActivityDocList();
        try {
            BulkRequest bulkRequest = new BulkRequest();

            for (ActivityDoc activity : activities) {

                // 创建IndexRequest
                IndexRequest indexRequest = new IndexRequest("voluntary_activities")
                        .id(String.valueOf(activity.getActivityId()))
                        .source(JSON.toJSONString(activity), XContentType.JSON);

                bulkRequest.add(indexRequest);
            }

            // 执行批量操作
            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);

            if (bulkResponse.hasFailures()) {
                log.warn("批量保存到Elasticsearch时存在失败记录: {}", bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            log.error("批量保存到Elasticsearch时发生IO错误", e);
            throw new CustomException("数据保存失败");
        }
    }

    @Override
    public PageResult<VoluntaryManagementVO> getVoluntaryManagementList(ActivityQueryDTO queryDTO) {
        PageHelper.startPage(queryDTO.getPageNum(), queryDTO.getPageSize());
        Page<VoluntaryManagementVO> pages = volunteerActivitiesMapper.selectVoluntaryManagementList(queryDTO);
        PageResult<VoluntaryManagementVO> pageResult = new PageResult<>(pages.getTotal(), pages.getResult());
        return pageResult;
    }

    /**
     * 审核志愿活动
     *
     * @param auditDTO
     */
    @Override
    public void auditVoluntaryActivity(ActivityAuditDTO auditDTO) throws IOException, WriterException {
        if (auditDTO.getAuditStatus() == 2 && auditDTO.getAuditReason() == null) {
            throw new CustomException("请填写审核失败原因");
        }
        VolunteerActivities volunteerActivities = new VolunteerActivities();
        BeanUtils.copyProperties(auditDTO, volunteerActivities);
        volunteerActivities.setAuditTime(LocalDateTime.now());
        volunteerActivities.setAuditEmployeeId(BaseContext.getCurrentId());
        volunteerActivitiesMapper.auditVoluntaryActivity(volunteerActivities);

        // 如果审核通过，发送延迟消息生成签到二维码等
        if (auditDTO.getAuditStatus() == 1) {
            rabbitTemplate.convertAndSend(MQConstants.DELAY_EXCHANGE_NAME,
                    MQConstants.DELAY_ACTIVITY_KEY, auditDTO.getActivityId());
        }

    }

    @Override
    public AuditVO getAudit(Integer activityId) {
        VolunteerActivities volunteerActivities = volunteerActivitiesMapper.selectById(activityId);
        AuditVO auditVO = new AuditVO();
        BeanUtils.copyProperties(volunteerActivities, auditVO);
        // TODO 获取审核人信息
        return auditVO;
    }

    /**
     * 签到签退
     *
     * @param activityId
     */

   @Override
public void signInOrSignOut(Integer activityId) {
    Integer status = volunteerParticipationMapper.selectParticipationStatus(activityId, BaseContext.getCurrentId());
    VolunteerActivities activity = volunteerActivitiesMapper.selectById(activityId);
    if (activity == null) {
        throw new CustomException("活动不存在");
    }
    VolunteerParticipation participation = new VolunteerParticipation();
    participation.setActivityId(activityId);
    participation.setUserId(BaseContext.getCurrentId());
    participation.setUpdatedAt(LocalDateTime.now());

    if (status == null) {
        throw new CustomException("您未报名该活动，无法进行签到/签退");
    }
    if (status == 0) {
        // 未签到
        // 判断活动是否开始
        if (activity.getStartTime().isAfter(LocalDateTime.now())) {
            throw new CustomException("活动尚未开始，无法签到");
        }
        // 检查是否已过签到时间（活动开始后1小时）
        if (activity.getStartTime().isBefore(LocalDateTime.now().minusHours(1))) {
            throw new CustomException("活动开始已超过1小时，无法签到");
        }

        // 防止短时间内重复扫码签到，检查最近2分钟内是否有签到记录
        VolunteerParticipation currentParticipation = volunteerParticipationMapper
                .selectByActivityIdAndUserId(activityId, BaseContext.getCurrentId());
        if (currentParticipation != null && currentParticipation.getSignInTime() != null) {
            if (currentParticipation.getSignInTime().isAfter(LocalDateTime.now().minusMinutes(2))) {
                throw new CustomException("请勿频繁扫码签到");
            }
        }
        participation.setParticipationStatus(1);
        participation.setSignInTime(LocalDateTime.now());
        volunteerParticipationMapper.updateActivity(participation);
    } else if (status == 1) {
        // 已签到状态，执行签退操作
        // 判断是否已到签退时间（活动开始后）
        if (activity.getStartTime().isAfter(LocalDateTime.now())) {
            throw new CustomException("活动尚未开始，无法签退");
        }

        // 检查是否活动已结束超过1小时
        if (activity.getEndTime().isBefore(LocalDateTime.now().minusHours(1))) {
            throw new CustomException("活动结束已超过1小时，无法签退");
        }

        // 防止签到后立即签退 - 检查签到时间是否在5分钟内
        VolunteerParticipation currentParticipation = volunteerParticipationMapper
                .selectByActivityIdAndUserId(activityId, BaseContext.getCurrentId());
        if (currentParticipation != null && currentParticipation.getSignInTime() != null) {
            if (currentParticipation.getSignInTime().isAfter(LocalDateTime.now().minusMinutes(5))) {
                throw new CustomException("签到后5分钟内无法签退，请稍后再试");
            }
        }

        // 防止短时间内重复扫码签退
        if (currentParticipation != null && currentParticipation.getSignOutTime() != null) {
            if (currentParticipation.getSignOutTime().isAfter(LocalDateTime.now().minusMinutes(2))) {
                throw new CustomException("请勿频繁扫码签退");
            }
        }

        participation.setParticipationStatus(2);
        participation.setSignOutTime(LocalDateTime.now());

        // 计算服务时长（小时）
        if (currentParticipation != null && currentParticipation.getSignInTime() != null) {
            long duration = java.time.Duration.between(
                    currentParticipation.getSignInTime(),
                    participation.getSignOutTime()).toHours();
            participation.setDuration((int) duration);
        }

        volunteerParticipationMapper.updateActivity(participation);
    } else if (status == 2) {
        // 已签退状态
        throw new CustomException("您已完成本次活动，无法重复操作");
    }
}

    @Override
    public void deleteElasticsearchData(String indexName) {
        try {
            DeleteByQueryRequest request = new DeleteByQueryRequest(indexName);
            request.setQuery(QueryBuilders.matchAllQuery());
            client.deleteByQuery(request, RequestOptions.DEFAULT);
            log.info("索引 {} 中的所有文档已删除", indexName);
        } catch (IOException e) {
            log.error("删除索引 {} 中的所有文档时发生错误", indexName, e);
            throw new CustomException("清空索引文档失败");
        }
    }

    /**
     * 获取用户创建的活动
     *
     * @return
     */
    @Override
    public List<CreatedActivityVO> getMyCreatedActivities() {
        Long userId = BaseContext.getCurrentId();
        return volunteerActivitiesMapper.selectCreatedActivitiesByUserId(userId);

    }

    /**
     * 获取用户参与活动
     *
     * @return
     */
    @Override
    public List<ParticipatedActivityVO> getMyParticipatedActivities() {
        Long userId = BaseContext.getCurrentId();
        return volunteerActivitiesMapper.selectParticipatedActivitiesByUserId(userId);
    }

}
